package com.xjrh.traintravel.collector.runner;

import com.xjrh.traintravel.collector.api.BusinessTrainService;
import com.xjrh.traintravel.collector.netty.ServerChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetSocketAddress;

/**
 * Netty服务端
 *
 * @author snps
 * @create 2022-01-17 11:48
 * @describe
 **/
@Component
@Order(value=2)
@Slf4j
public class NettyServer implements CommandLineRunner {

    /**
     * NettyServer.url
     */
    @Value("${netty.server.url}")
    private String url;

    /**
     * NettyServer.port
     */
    @Value("${netty.server.port}")
    private int port;

    /**
     * 连接处理器
     */
    private EventLoopGroup bossGroup;

    /**
     * 事件处理器
     */
    private EventLoopGroup workerGroup;

    /**
     * ServerChannel
     */
    private static Channel serverChannel;

    /**
     * Netty服务端初始化
     */
    @Resource
    private ServerChannelInitializer serverChannelInitializer;

    @Resource
    private BusinessTrainService businessTrainService;


    @Override
    public void run(String... args) throws Exception {
        log.warn("----------------------------------------");
        log.warn("NettyServer run...");

        InetSocketAddress ipAddress = new InetSocketAddress(url, port);
        log.warn("server ipAddress is: {}", ipAddress.toString());

        ChannelFuture channelFuture = this.start(port);

        log.warn("NettyServer run success!");
        log.warn("----------------------------------------");
    }


    /**
     * 启动NettyServer
     * @param port 服务器运行端口
     * @throws Exception
     */
    public ChannelFuture start(int port) throws Exception {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();

        ChannelFuture channelFuture = null;

        try {
            // 配置服务器
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    // 指定使用NioServerSocketChannel产生一个Channel用来接收连接
                    .channel(NioServerSocketChannel.class)
                    // 用于配置一个新的Channel
                    .childHandler(serverChannelInitializer)
                    // 当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 是否启用心跳保活机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            log.warn("NettyServer start...");

            // 绑定端口，接收连接
            channelFuture = serverBootstrap.bind(port).sync();
            serverChannel = channelFuture.channel();

            // 创建监听，优雅关闭Netty资源
            channelFuture.channel().closeFuture().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();

                    if (serverChannel != null) {
                        serverChannel.close();
                        serverChannel = null;
                    }
                }
            });
            // ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            // channelFuture.channel().closeFuture().sync();

            log.warn("NettyServer start success!");
        } finally {
        }

        return channelFuture;
    }


    /**
     * 停止NettyServer
     */
    public final void stop() {
        log.warn("NettyServer stop...");

        // 释放资源
        if (serverChannel != null) {
            serverChannel.close();
            serverChannel = null;
        }

        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();

        // 设置全部设备为离线状态
        businessTrainService.setAllOffLine();

        log.warn("NettyServer stop success!");
    }

}